/*
    Copyright (c) 2009 Pavol Malosek a.k.a. malo

    This file is part of ComComLib.

    ComComLib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ComComLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <lcc/device_Rxxxx.hpp>
#include <lcc/command.hpp>
#include <lcc/dlparser.hpp>

#include <iostream>
#include <assert.h>

//#define LCC_RDEVICE_DEBUG
//#define LCC_RDEVICE_DEBUG_LEVEL 4

// level 1 = key behaviour
// level 2 = processing flow
// level 4 = infos

#ifndef LCC_RDEVICE_DEBUG
#   define lcc_log(n, ...)  while (0)
#else
#   define lcc_log(n, ...)    do { if ((n) <= LCC_RDEVICE_DEBUG_LEVEL) \
                                { printf (__VA_ARGS__);}} while (0)
#endif

lcc::device_Rxxxx_t::device_Rxxxx_t (const char *tty_)
{
    snprintf (tty_name, sizeof (tty_name) - 1, "%s", tty_);
}

lcc::device_Rxxxx_t::~device_Rxxxx_t (void)
{
    if (service_memory)
        delete [] service_memory;
    if (data_memory)
        delete [] data_memory;
}

lcc::logger_command_status_t lcc::device_Rxxxx_t::touch (void)
{
    //  Open tty.
    int rc = open_tty ();
    if (rc == -1)
        return status_failed;

    bool bogus_ok = bogus_command ();

    close_tty ();

    if (!bogus_ok)
        return status_failed;
    
    return status_ok;
}

lcc::logger_command_status_t lcc::device_Rxxxx_t::read_service_memory (void)
{
    //  Open tty.
    int rc = open_tty ();
    if (rc == -1)
        return status_failed;
    
    //  If we are reading service memory firs time have to allocate memory.
    if (!service_memory)
        service_memory = new unsigned char [512];
    
    //  First 256B
    rc = read_256_EE (service_memory, 0x00);
    if (rc != 256)
        return status_failed;

    //  Second 256B
    rc = read_256_EE (service_memory + 0x100, 0x100);
    if (rc != 256)
        return status_failed;

    //  Read status word.
    rc = read_status_word ();
    if (rc != sizeof (uint16_t))
        return status_failed;

    close_tty ();

    //  Parse service memory and update device_info struct.
    if (!update_device_info ()) {
        return status_failed;
    }

    return status_ok;
}

lcc::logger_command_status_t 
    lcc::device_Rxxxx_t::read_data_memory (uint16_t src_addr_, size_t size_,
    bool keep_tty_open_)
{
    //  Open tty.
    int rc = open_tty ();
    if (rc == -1)
        return status_failed;
   
    //  Delete data buff from previous read
    if (data_memory)
        delete [] data_memory;

    data_memory = new unsigned char [size_ + 1];
    memset (data_memory, '\0', size_ + 1);

    //  Currently we can read only 256B:(
    if (size_ == 0xff)
        rc = read_256_EE (data_memory, src_addr_);
    else
        assert (false);

    if (rc != (int) size_ + 1) {
        close_tty ();
        return status_failed;
    }

    close_tty (keep_tty_open_);

    return status_ok;
}

lcc::logger_command_status_t lcc::device_Rxxxx_t::read_records (void)
{

    lcc_log (4, "Going to read records, %s(%i)\n", __FILE__, __LINE__);

    lcc_log (4, "Reread service memory, %s(%i)\n", __FILE__, __LINE__);

    //  Rereding service memory & update device_info.
    if (read_service_memory () != status_ok)
        return status_failed;

    lcc_log (4, "Read data memory, %s(%i)\n", __FILE__, __LINE__);
  
    //  Clenup records list.
    records.clear ();

    //  Position, data memory starts at 0x200h
    size_t read_offset = 0x200;

    //  Alread read.
    size_t read = 0;

    //  We will read 256B blocks.
    size_t read_block = 0xff;    

    //  Create parser.
    parser_t parser (&device_info);

    //  Read entire logger data memory.
    while (read < device_info.data_memory_size) {
        
        if (read_data_memory (read + read_offset, 0xff, true) != status_ok) {
            return status_failed; 
        }
        
        read += read_block + 1;

        parser.parse (data_memory, 0xff);

        //  If no records were produced from recent logger data,
        //  exit from parsing.
        if (parser.flush_records (this) == 0) {
            lcc_log (4, "No records produced, exiting parsing, %s(%i)\n",
                __FILE__, __LINE__);
            break;
        }
        
        //break;
    }

    //  Close tty
    close_tty ();
    
    return status_ok;
}

